home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / Online / Term / Extras / Source / gtlayout-source.lha / LTP_PopupClass.c < prev    next >
C/C++ Source or Header  |  1996-10-03  |  24KB  |  1,150 lines

  1. /*
  2. **    GadTools layout toolkit
  3. **
  4. **    Copyright © 1993-1996 by Olaf `Olsen' Barthel
  5. **        Freely distributable.
  6. **
  7. **    :ts=4
  8. */
  9.  
  10. #ifndef _GTLAYOUT_GLOBAL_H
  11. #include "gtlayout_global.h"
  12. #endif
  13.  
  14. #if defined(DO_POPUP_KIND) && defined(DO_BOOPSI_KIND)
  15.  
  16. #define PIF_SingleActive    (1 << 0)
  17. #define PIF_ArrowUp            (1 << 1)
  18. #define PIF_ArrowDown        (1 << 2)
  19.  
  20. STATIC VOID
  21. DrawArrow(struct RastPort *RPort,LONG Left,LONG Top,LONG ArrowWidth,LONG ArrowHeight,LONG Dir)
  22. {
  23.     LONG i,Width,Start,Pos;
  24.  
  25.     for(i = 0 ; i < ArrowHeight ; i++)
  26.     {
  27.         Width = ((ArrowWidth * (i + 1)) / ArrowHeight) & ~1;
  28.  
  29.         if(Width < ArrowWidth)
  30.             Width++;
  31.  
  32.         Start = Left + (ArrowWidth - Width) / 2;
  33.  
  34.         if(Dir < 0)
  35.             Pos = Top + i;
  36.         else
  37.             Pos = Top + ArrowHeight - 1 - i;
  38.  
  39.         LTP_DrawLine(RPort,Start,Pos,Start + Width - 1,Pos);
  40.     }
  41. }
  42.  
  43. STATIC VOID
  44. DrawContainer(struct RastPort *RPort,LONG Left,LONG Top,LONG Width,LONG Height,struct GadgetInfo *GadgetInfo,PopInfo *Info,UWORD Highlight,UWORD Disabled)
  45. {
  46.     LONG Shine,Shadow,Txt,Fill;
  47.     UWORD *Pens;
  48.  
  49.     Pens = GadgetInfo->gi_DrInfo->dri_Pens;
  50.  
  51.     if(Highlight)
  52.     {
  53.         Shine    = Pens[SHADOWPEN];
  54.         Shadow    = Pens[SHINEPEN];
  55.         Txt        = Pens[FILLTEXTPEN];
  56.         Fill    = Pens[FILLPEN];
  57.     }
  58.     else
  59.     {
  60.         Shine    = Pens[SHINEPEN];
  61.         Shadow    = Pens[SHADOWPEN];
  62.         Txt        = Pens[TEXTPEN];
  63.         Fill    = Pens[BACKGROUNDPEN];
  64.     }
  65.  
  66.     LTP_SetPens(RPort,Fill,0,JAM1);
  67.  
  68.     LTP_FillBox(RPort,Left + 2,Top + 1,Width - 4,Height - 2);
  69.  
  70.     LTP_RenderBevel(RPort,Pens,Left,Top,Width,Height,Highlight,2);
  71.  
  72.     LTP_SetAPen(RPort,Shadow);
  73.     LTP_DrawLine(RPort,Left + Info->MarkLeft,Top + 2,Left + Info->MarkLeft,Top + Height - 3);
  74.  
  75.     LTP_SetAPen(RPort,Shine);
  76.     LTP_DrawLine(RPort,Left + Info->MarkLeft + 1,Top + 2,Left + Info->MarkLeft + 1,Top + Height - 3);
  77.  
  78.     SetFont(RPort,Info->Font);
  79.     LTP_SetAPen(RPort,Txt);
  80.  
  81.     DrawArrow(RPort,Left + 4,Top + Info->ArrowTop,Info->ArrowWidth,Info->ArrowHeight,1);
  82.  
  83.     LTP_PrintText(RPort,Info->Labels[Info->Active],Info->ActiveLen,Left + Info->LabelLeft,Top + Info->LabelTop);
  84.  
  85.     if(Disabled)
  86.         LTP_GhostBox(RPort,Left,Top,Width,Height,Pens[SHADOWPEN]);
  87. }
  88.  
  89. STATIC VOID
  90. DrawOneBox(PopInfo *Info,LONG Top,LONG Index)
  91. {
  92.     struct RastPort    *RPort;
  93.     LONG             Len;
  94.     LONG             Extra;
  95.     STRPTR             Label;
  96.  
  97.     Label = Info->Labels[Index];
  98.  
  99.     RPort = Info->Window->RPort;
  100.  
  101.     if((Len = strlen(Label)) > Info->MaxLen)
  102.         Len = Info->MaxLen;
  103.  
  104.     if(Info->CheckGlyph)
  105.         Extra = Info->CheckGlyph->Width + 2;
  106.     else
  107.         Extra = 0;
  108.  
  109.     LTP_PrintText(RPort,Label,Len,6 + Extra,Top + Info->LineTop);
  110.  
  111.     if(Extra && Index == Info->InitialActive)
  112.         LTP_DrawCheckGlyph(RPort,6,Top + Info->LineTop,Info->CheckGlyph,Index == Info->LastLabelDrawn);
  113. }
  114.  
  115. STATIC VOID
  116. DrawOneGlyph(PopInfo *Info,LONG Top,LONG Dir,UWORD *Pens)
  117. {
  118.     struct RastPort *RPort;
  119.  
  120.     RPort = Info->Window->RPort;
  121.  
  122.     if(Pens)
  123.     {
  124.         LTP_SetAPen(RPort,Info->MenuBack);
  125.         LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  126.         LTP_SetAPen(RPort,Info->MenuText);
  127.     }
  128.  
  129.     DrawArrow(RPort,6,Top + Info->ArrowTop,Info->ArrowWidth,Info->ArrowHeight,Dir);
  130. }
  131.  
  132. STATIC VOID
  133. BoxRender(PopInfo *Info,UWORD *Pens,LONG Active,BOOL FullRefresh,BOOL Highlight,LONG Dir)
  134. {
  135.     struct RastPort *RPort = Info->Window->RPort;
  136.  
  137.     if(FullRefresh)
  138.     {
  139.         LONG Index,Top;
  140.         LONG Width,Height;
  141.  
  142.         LTP_SetPens(RPort,Info->MenuBack,0,JAM1);
  143.  
  144.         Width    = Info->Window->Width;
  145.         Height    = Info->Window->Height;
  146.  
  147.         LTP_FillBox(RPort,2,1,Width - 4,Height - 2);
  148.  
  149.         LTP_SetAPen(RPort,Info->MenuText);
  150.  
  151.         LTP_PolyDraw(RPort,5,
  152.             1,1,
  153.             1,Height - 2,
  154.             0,Height - 2,
  155.             0,0,
  156.             Width - 1,0);
  157.  
  158.         LTP_PolyDraw(RPort,5,
  159.             0,Height - 1,
  160.             Width - 1,Height - 1,
  161.             Width - 1,1,
  162.             Width - 2,1,
  163.             Width - 2,Height - 2);
  164.  
  165.         Index    = Info->TopMost;
  166.         Top        = 2;
  167.         Height    = Info->BoxHeight;
  168.  
  169.         Info->Flags &= ~(PIF_ArrowUp | PIF_ArrowDown);
  170.  
  171.         if(Info->TopMost > 0 && Active != Info->TopMost && Info->BoxLines > 2)
  172.         {
  173.             Info->Flags |= PIF_ArrowUp;
  174.  
  175.             Index    += 1;
  176.             Top        += Info->SingleHeight;
  177.             Height    -= Info->SingleHeight;
  178.         }
  179.  
  180.         if(Info->TopMost + Info->BoxLines < Info->NumLabels && Active != Info->TopMost + Info->BoxLines - 1 && Info->BoxLines > 2)
  181.         {
  182.             Info->Flags |= PIF_ArrowDown;
  183.  
  184.             Height -= Info->SingleHeight;
  185.         }
  186.  
  187.         Info->LastLabelDrawn = Active;    // IMPORTANT: must be set up here to DrawOneBox can find it
  188.  
  189.         for( ; Index < Info->NumLabels && Height > 0 ; Index++, Top += Info->SingleHeight, Height -= Info->SingleHeight)
  190.         {
  191.             if(Index == Active)
  192.             {
  193.                 LTP_SetAPen(RPort,Info->MenuBackSelect);
  194.                 LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  195.  
  196.                 LTP_SetAPen(RPort,Info->MenuTextSelect);
  197.                 DrawOneBox(Info,Top,Index);
  198.  
  199.                 LTP_SetAPen(RPort,Info->MenuText);
  200.             }
  201.             else
  202.                 DrawOneBox(Info,Top,Index);
  203.         }
  204.  
  205.         if(Info->Flags & PIF_ArrowUp)
  206.             DrawOneGlyph(Info,2,-1,NULL);
  207.  
  208.         if(Info->Flags & PIF_ArrowDown)
  209.             DrawOneGlyph(Info,2 + (Info->BoxLines - 1) * Info->SingleHeight,1,NULL);
  210.  
  211.         Info->LastDrawn = 2 + (Active - Info->TopMost) * Info->SingleHeight;
  212.     }
  213.     else
  214.     {
  215.         if(Info->LastLabelDrawn != -1)
  216.         {
  217.             LONG Top = Info->LastDrawn,Last = Info->LastLabelDrawn;
  218.  
  219.             Info->LastLabelDrawn = -1;
  220.  
  221.             LTP_SetPens(RPort,Info->MenuBack,0,JAM1);
  222.             LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  223.             LTP_SetAPen(RPort,Info->MenuText);
  224.  
  225.             DrawOneBox(Info,Top,Last);
  226.         }
  227.  
  228.         Info->LastDrawn = -1;
  229.  
  230.         if(Active >= 0)
  231.         {
  232.             LONG Top,NewActive;
  233.  
  234.             NewActive    = Active - Info->TopMost;
  235.             Top            = 2 + NewActive * Info->SingleHeight;
  236.  
  237.             if(Top >= 2 && Top < Info->BoxHeight + 2)
  238.             {
  239.                 LONG Pen;
  240.  
  241.                 if(Dir != 0)
  242.                     Highlight = FALSE;
  243.  
  244.                 if(Highlight)
  245.                 {
  246.                     Pen = Info->MenuBackSelect;
  247.  
  248.                     Info->LastDrawn            = Top;
  249.                     Info->LastLabelDrawn    = Active;
  250.                 }
  251.                 else
  252.                     Pen = Info->MenuBack;
  253.  
  254.                 LTP_SetPens(RPort,Pen,0,JAM1);
  255.                 LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  256.  
  257.                 if(Highlight)
  258.                     Pen = Info->MenuTextSelect;
  259.                 else
  260.                     Pen = Info->MenuText;
  261.  
  262.                 LTP_SetAPen(RPort,Pen);
  263.  
  264.                 if(Dir == 0)
  265.                     DrawOneBox(Info,Top,Active);
  266.                 else
  267.                     DrawOneGlyph(Info,Top,Dir,NULL);
  268.             }
  269.         }
  270.     }
  271. }
  272.  
  273. STATIC ULONG
  274. InputMethod(struct IClass *class,struct Gadget *gadget,struct gpInput *InputInfo)
  275. {
  276.     PopInfo    *Info    = INST_DATA(class,gadget);
  277.     ULONG     Result    = GMR_MEACTIVE;
  278.     BOOL     Done    = FALSE;
  279.     BOOL     Redraw    = FALSE;
  280.  
  281.     if(InputInfo->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
  282.     {
  283.         UWORD Code = InputInfo->gpi_IEvent->ie_Code;
  284.  
  285.         if(Code == MENUDOWN)
  286.         {
  287.             Result    = GMR_NOREUSE;
  288.             Done    = TRUE;
  289.  
  290.             Info->Active = Info->InitialActive;
  291.         }
  292.         else
  293.         {
  294.             if(Code == SELECTUP)
  295.             {
  296.                 Done = TRUE;
  297.  
  298.                 if(Info->Active < 0)
  299.                 {
  300.                     Result = GMR_NOREUSE;
  301.  
  302.                     Info->Active = Info->InitialActive;
  303.                 }
  304.                 else
  305.                 {
  306.                     LONG Len;
  307.  
  308.                     Result = GMR_NOREUSE | GMR_VERIFY;
  309.  
  310.                     if(Info->Flags & PIF_SingleActive)
  311.                     {
  312.                         LONG Width,Height;
  313.                         LONG x,y;
  314.  
  315.                         x = InputInfo->gpi_Mouse.X;
  316.                         y = InputInfo->gpi_Mouse.Y;
  317.  
  318.                         Width    = gadget->Width;
  319.                         Height    = gadget->Height;
  320.  
  321.                         if(x >= 0 && y >= 0 && x < Width && y < Height)
  322.                         {
  323.                             if(InputInfo->gpi_IEvent->ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  324.                                 Info->Active--;
  325.                             else
  326.                                 Info->Active++;
  327.  
  328.                             if(Info->Active >= Info->NumLabels)
  329.                                 Info->Active = 0;
  330.                             else
  331.                             {
  332.                                 if(Info->Active < 0)
  333.                                     Info->Active = Info->NumLabels - 1;
  334.                             }
  335.                         }
  336.                         else
  337.                         {
  338.                             Result = GMR_NOREUSE;
  339.  
  340.                             Info->Active = Info->InitialActive;
  341.                         }
  342.                     }
  343.  
  344.                     Len = strlen(Info->Labels[Info->Active]);
  345.  
  346.                     if(Len > Info->MaxLen)
  347.                         Len = Info->MaxLen;
  348.  
  349.                     Info->ActiveLen = Len;
  350.  
  351.                     *InputInfo->gpi_Termination = Info->Active;
  352.                 }
  353.             }
  354.             else
  355.             {
  356.                 if(Info->Flags & PIF_SingleActive)
  357.                 {
  358.                     LONG Width,Height;
  359.                     LONG x,y;
  360.                     BOOL RefreshIt = FALSE;
  361.  
  362.                     x = InputInfo->gpi_Mouse.X;
  363.                     y = InputInfo->gpi_Mouse.Y;
  364.  
  365.                     Width    = gadget->Width;
  366.                     Height    = gadget->Height;
  367.  
  368.                     if(x < 0 || y < 0 || x >= Width || y >= Height)
  369.                     {
  370.                         if(gadget->Flags & GFLG_SELECTED)
  371.                             RefreshIt = TRUE;
  372.                     }
  373.                     else
  374.                     {
  375.                         if(!(gadget->Flags & GFLG_SELECTED))
  376.                             RefreshIt = TRUE;
  377.                     }
  378.  
  379.                     if(RefreshIt)
  380.                     {
  381.                         gadget->Flags ^= GFLG_SELECTED;
  382.  
  383.                         Redraw = TRUE;
  384.                     }
  385.                 }
  386.             }
  387.         }
  388.  
  389.         if(Done)
  390.         {
  391.             if(gadget->Flags & GFLG_SELECTED)
  392.             {
  393.                 gadget->Flags &= ~GFLG_SELECTED;
  394.                 Redraw = TRUE;
  395.             }
  396.  
  397.             if(Info->Window)
  398.             {
  399.                 CloseWindow(Info->Window);
  400.                 Info->Window = NULL;
  401.             }
  402.  
  403.             LTP_DeleteCheckGlyph(Info->CheckGlyph);
  404.             Info->CheckGlyph = NULL;
  405.  
  406.             Info->Flags &= ~PIF_SingleActive;
  407.         }
  408.     }
  409.  
  410.     if(!Done && Info->Window)
  411.     {
  412.         LONG    NewActive = 0;
  413.         LONG    x,y;
  414.         LONG    Dir = 0;
  415.         LONG    From,To;
  416.  
  417.         x = InputInfo->gpi_GInfo->gi_Screen->MouseX - Info->BoxLeft;
  418.         y = InputInfo->gpi_GInfo->gi_Screen->MouseY - Info->BoxTop;
  419.  
  420.         if(x < 0 || x >= Info->BoxWidth)
  421.             NewActive = -1;
  422.         else
  423.         {
  424.             LONG Margin;
  425.  
  426.             if(Info->Flags & (PIF_ArrowUp | PIF_ArrowDown))
  427.                 Margin = Info->SingleHeight;
  428.             else
  429.                 Margin = (Info->SingleHeight + 3) / 4;
  430.  
  431.                 // Scroll up?
  432.  
  433.             if(y < Margin)
  434.             {
  435.                 if(y < 0)
  436.                     NewActive = -1;
  437.                 else
  438.                 {
  439.                         // Topmost line concealed?
  440.  
  441.                     if(Info->TopMost > 0)
  442.                     {
  443.                         Info->TopMost--;
  444.  
  445.                         From    = 2;
  446.                         To        = 2 + Info->BoxHeight - 1;
  447.  
  448.                         Dir = -Info->SingleHeight;
  449.                     }
  450.                 }
  451.             }
  452.             else
  453.             {
  454.                 LONG Last;
  455.  
  456.                 Last = Info->NumLabels - Info->TopMost;
  457.  
  458.                 if(Last < Info->BoxLines)
  459.                     Last = Last * Info->SingleHeight;
  460.                 else
  461.                     Last = Info->BoxHeight;
  462.  
  463.                     // Scroll up?
  464.  
  465.                 if(y >= Last - Margin)
  466.                 {
  467.                     if(y >= Last)
  468.                         NewActive = -1;
  469.                     else
  470.                     {
  471.                             // Last line concealed?
  472.  
  473.                         if(Info->TopMost + Info->BoxLines < Info->NumLabels)
  474.                         {
  475.                             Info->TopMost++;
  476.  
  477.                             From    = 2;
  478.                             To        = 2 + Info->BoxHeight - 1;
  479.  
  480.                             Dir = Info->SingleHeight;
  481.                         }
  482.                     }
  483.                 }
  484.             }
  485.  
  486.             if(NewActive != -1)
  487.             {
  488.                 NewActive = Info->TopMost + y / Info->SingleHeight;
  489.  
  490.                 if(NewActive < 0)
  491.                     NewActive = 0;
  492.                 else
  493.                 {
  494.                     if(NewActive >= Info->NumLabels)
  495.                         NewActive = Info->NumLabels - 1;
  496.                 }
  497.             }
  498.         }
  499.  
  500.         if(NewActive != Info->Active || Dir != 0)
  501.         {
  502.             LONG     Arrow;
  503.             UWORD    *Pens = InputInfo->gpi_GInfo->gi_DrInfo->dri_Pens;
  504.  
  505.             if(Dir != 0)
  506.             {
  507.                 struct RastPort *RPort = Info->Window->RPort;
  508.  
  509.                 Arrow = (NewActive == Info->TopMost) ? -1 : 1;
  510.  
  511.                 BoxRender(Info,Pens,-1,FALSE,FALSE,0);
  512.  
  513.                 if(Info->Flags & PIF_ArrowUp)
  514.                     From += Info->SingleHeight;
  515.  
  516.                 if(Info->Flags & PIF_ArrowDown)
  517.                     To -= Info->SingleHeight;
  518.  
  519.                 SetBPen(RPort,Pens[BACKGROUNDPEN]);
  520.                 ScrollRaster(RPort,0,Dir,4,From,4 + Info->BoxWidth - 1,To);
  521.  
  522.                 if(Dir < 0)
  523.                     BoxRender(Info,Pens,Info->TopMost + 1,FALSE,FALSE,0);
  524.                 else
  525.                     BoxRender(Info,Pens,Info->TopMost + Info->BoxLines - 2,FALSE,FALSE,0);
  526.  
  527.                 if(!Info->TopMost || Info->BoxLines < 3)
  528.                 {
  529.                     Info->Flags &= ~PIF_ArrowUp;
  530.  
  531.                     Arrow = 0;
  532.                 }
  533.                 else
  534.                 {
  535.                     if(!(Info->Flags & PIF_ArrowUp))
  536.                     {
  537.                         Info->Flags |= PIF_ArrowUp;
  538.  
  539.                         DrawOneGlyph(Info,2,-1,Pens);
  540.                     }
  541.                 }
  542.  
  543.                 if(Info->TopMost + Info->BoxLines >= Info->NumLabels || Info->BoxLines < 3)
  544.                 {
  545.                     Info->Flags &= ~PIF_ArrowDown;
  546.  
  547.                     Arrow = 0;
  548.                 }
  549.                 else
  550.                 {
  551.                     if(!(Info->Flags & PIF_ArrowDown))
  552.                     {
  553.                         Info->Flags |= PIF_ArrowDown;
  554.  
  555.                         DrawOneGlyph(Info,2 + (Info->BoxLines - 1) * Info->SingleHeight,1,Pens);
  556.                     }
  557.                 }
  558.             }
  559.             else
  560.                 Arrow = 0;
  561.  
  562.             Info->Active = NewActive;
  563.  
  564.             BoxRender(Info,Pens,NewActive,FALSE,TRUE,Arrow);
  565.         }
  566.     }
  567.  
  568.     if(Redraw)
  569.     {
  570.         struct RastPort    *RPort;
  571.  
  572.         if(RPort = ObtainGIRPort(InputInfo->gpi_GInfo))
  573.         {
  574.             DoMethod((Object *)gadget,GM_RENDER,InputInfo->gpi_GInfo,RPort,GREDRAW_UPDATE);
  575.             ReleaseGIRPort(RPort);
  576.         }
  577.     }
  578.  
  579.     return(Result);
  580. }
  581.  
  582. STATIC VOID
  583. SetMethod(struct IClass *class,struct Gadget *gadget,struct opSet *SetInfo)
  584. {
  585.     PopInfo            *Info = INST_DATA(class,gadget);
  586.     struct TagItem    *This;
  587.     LONG             NewActive;
  588.     STRPTR            *NewLabels;
  589.     UWORD             Flags = gadget -> Flags;
  590.     BOOL             NeedRefresh = FALSE;
  591.     LONG             LabelCount;
  592.  
  593.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  594.  
  595.     DoSuperMethodA(class,(Object *)gadget,(Msg)SetInfo);
  596.  
  597.     if(This = FindTagItem(GA_Disabled,SetInfo->ops_AttrList))
  598.     {
  599.         if(This -> ti_Data && !(Flags & GFLG_DISABLED) || !This -> ti_Data && (Flags & GFLG_DISABLED))
  600.             NeedRefresh = TRUE;
  601.     }
  602.  
  603.     if(NewLabels = (STRPTR *)GetTagData(PIA_Labels,NULL,SetInfo->ops_AttrList))
  604.         for(LabelCount = 0 ; NewLabels[LabelCount] != NULL ; LabelCount++);
  605.     else
  606.         LabelCount = Info->NumLabels;
  607.  
  608.     if(This = FindTagItem(PIA_Active,SetInfo->ops_AttrList))
  609.     {
  610.         NewActive = (LONG)This->ti_Data;
  611.  
  612.         if(NewActive < 0)
  613.             NewActive = 0;
  614.         else
  615.         {
  616.             if(NewActive >= LabelCount)
  617.                 NewActive = LabelCount - 1;
  618.         }
  619.     }
  620.     else
  621.         NewActive = -1;
  622.  
  623.     if((NewActive != Info->Active && NewActive != -1) || NewLabels)
  624.     {
  625.         if(NewLabels == (STRPTR *)~0)
  626.             Info->Blocked = TRUE;
  627.         else
  628.         {
  629.             struct RastPort *RPort;
  630.  
  631.             Info->Blocked = FALSE;
  632.  
  633.             if(RPort = ObtainGIRPort(SetInfo->ops_GInfo))
  634.             {
  635.                 LONG     Len;
  636.                 STRPTR    *Labels;
  637.                 LONG     MaxLen,ActiveLen;
  638.  
  639.                 if(NewLabels)
  640.                 {
  641.                     struct TextExtent Extent;
  642.                     LONG i;
  643.  
  644.                     for(i = 0, MaxLen = 0 ; i < LabelCount ; i++)
  645.                     {
  646.                         Len = TextFit(RPort,NewLabels[i],strlen(NewLabels[i]),&Extent,NULL,1,Info->MaxWidth,32767);
  647.  
  648.                         if(Len > MaxLen)
  649.                             MaxLen = Len;
  650.                     }
  651.  
  652.                     Labels = NewLabels;
  653.                 }
  654.                 else
  655.                 {
  656.                     Labels = Info->Labels;
  657.                     MaxLen = Info->MaxLen;
  658.                 }
  659.  
  660.                 if(NewActive == -1)
  661.                     NewActive = Info->Active;
  662.  
  663.                 if(NewActive >= LabelCount)
  664.                     NewActive = LabelCount - 1;
  665.  
  666.                 Len = strlen(Labels[NewActive]);
  667.  
  668.                 if(Len > MaxLen)
  669.                     Len = MaxLen;
  670.  
  671.                 ActiveLen = Len;
  672.  
  673.                 Info->Active    = NewActive;
  674.                 Info->ActiveLen    = ActiveLen;
  675.  
  676.                 if(NewLabels)
  677.                 {
  678.                     Info->Labels    = NewLabels;
  679.                     Info->NumLabels    = LabelCount;
  680.                     Info->MaxLen    = MaxLen;
  681.                 }
  682.  
  683.                 NeedRefresh = TRUE;
  684.  
  685.                 ReleaseGIRPort(RPort);
  686.             }
  687.         }
  688.     }
  689.  
  690.     if(!(gadget -> Flags & GFLG_DISABLED) && (This = FindTagItem(PIA_Highlight,SetInfo->ops_AttrList)))
  691.     {
  692.         if(This->ti_Data)
  693.             gadget->Flags |= GFLG_SELECTED;
  694.         else
  695.             gadget->Flags &= ~GFLG_SELECTED;
  696.  
  697.         NeedRefresh = TRUE;
  698.     }
  699.  
  700.     if(NeedRefresh)
  701.     {
  702.         struct RastPort *RPort;
  703.  
  704.         if(RPort = ObtainGIRPort(SetInfo->ops_GInfo))
  705.         {
  706.             DoMethod((Object *)gadget,GM_RENDER,SetInfo->ops_GInfo,RPort,GREDRAW_UPDATE);
  707.             ReleaseGIRPort(RPort);
  708.         }
  709.     }
  710. }
  711.  
  712. STATIC ULONG
  713. RenderMethod(struct IClass *class,struct Gadget *gadget,struct gpRender *RenderInfo)
  714. {
  715.     PopInfo    *Info = INST_DATA(class,gadget);
  716.  
  717.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  718.  
  719.     DrawContainer(RenderInfo->gpr_RPort,gadget->LeftEdge,gadget->TopEdge,gadget->Width,gadget->Height,RenderInfo->gpr_GInfo,Info,gadget->Flags & GFLG_SELECTED,gadget->Flags & GFLG_DISABLED);
  720.  
  721.     return(TRUE);
  722. }
  723.  
  724. STATIC VOID
  725. DisposeMethod(struct IClass *class,Object *object,Msg msg)
  726. {
  727.     PopInfo *Info = INST_DATA(class,object);
  728.  
  729.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  730.  
  731.     if(Info->Font)
  732.     {
  733.         CloseFont(Info->Font);
  734.         Info->Font = NULL;
  735.     }
  736.  
  737.     if(Info->Window)
  738.     {
  739.         CloseWindow(Info->Window);
  740.         Info->Window = NULL;
  741.     }
  742.  
  743.     LTP_DeleteCheckGlyph(Info->CheckGlyph);
  744.     Info->CheckGlyph = NULL;
  745. }
  746.  
  747. STATIC ULONG
  748. NewMethod(struct IClass *class,Object *object,struct opSet *SetInfo)
  749. {
  750.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  751.  
  752.     if(object = (Object *)DoSuperMethodA(class,object,(Msg)SetInfo))
  753.     {
  754.         PopInfo            *Info = INST_DATA(class,object);
  755.         struct TagItem    *Item,*TagList = SetInfo -> ops_AttrList;
  756.         struct TextAttr    *Font;
  757.         LONG             Width,Height;
  758.  
  759.         Width = Height = 0;
  760.         Font = NULL;
  761.  
  762.         memset(Info,0,sizeof(PopInfo));
  763.  
  764.         while(Item = NextTagItem(&TagList))
  765.         {
  766.             switch(Item->ti_Tag)
  767.             {
  768.                 case GA_Width:
  769.                     Width = Item->ti_Data;
  770.                     break;
  771.  
  772.                 case GA_Height:
  773.                     Height = Item->ti_Data;
  774.                     break;
  775.  
  776.                 case PIA_Labels:
  777.                     Info->Labels = (STRPTR *)Item->ti_Data;
  778.                     break;
  779.  
  780.                 case PIA_Active:
  781.                     Info->Active = (LONG)Item->ti_Data;
  782.                     break;
  783.  
  784.                 case PIA_Font:
  785.                     Font = (struct TextAttr *)Item->ti_Data;
  786.                     break;
  787.  
  788.                 case PIA_CentreActive:
  789.                     Info->CentreActive = Item->ti_Data;
  790.                     break;
  791.             }
  792.         }
  793.  
  794.         if(Font && Info->Labels && Info->Labels != (STRPTR *)~0 && Width && Height)
  795.         {
  796.             while(Info->Labels[Info->NumLabels])
  797.                 Info->NumLabels++;
  798.  
  799.             if(Info->NumLabels)
  800.             {
  801.                 if(Info->Font = OpenFont(Font))
  802.                 {
  803.                     struct RastPort RPort;
  804.  
  805.                     if(Info->Active < 0)
  806.                         Info->Active = 0;
  807.                     else
  808.                     {
  809.                         if(Info->Active >= Info->NumLabels)
  810.                             Info->Active = Info->NumLabels - 1;
  811.                     }
  812.  
  813.                     InitRastPort(&RPort);
  814.                     SetFont(&RPort,Info->Font);
  815.  
  816.                     Info->ArrowWidth    = (TextLength(&RPort,"M",1) & ~1) + 1;
  817.                     Info->ArrowHeight    = (2 * RPort.TxHeight) / 3;
  818.                     Info->ArrowTop        = (Height - Info->ArrowHeight) / 2;
  819.  
  820.                     Info->MarkLeft    = 4 + Info->ArrowWidth + 2;
  821.                     Info->MarkWidth    = Info->MarkLeft + 4;
  822. /*
  823.                     Info->PopLeft    = Info->MarkWidth - 6;
  824.                     Info->PopWidth    = Width - Info->PopLeft;
  825. */
  826.                     Info->PopLeft    = 0;
  827.                     Info->PopWidth    = Width;
  828.  
  829.                     Info->LabelTop    = (Height - RPort.TxHeight) / 2;
  830.                     Info->LabelLeft    = Info->MarkWidth;
  831.  
  832.                     Width    -= 6 + Info->MarkWidth + 6;
  833.                     Height    -= 2 + RPort.TxHeight + 2;
  834.  
  835.                     if(Width > 0 && Height >= 0)
  836.                     {
  837.                         struct TextExtent    Extent;
  838.                         LONG                i,Len,MaxLen;
  839.  
  840.                         for(i = MaxLen = 0 ; i < Info->NumLabels ; i++)
  841.                         {
  842.                             Len = TextFit(&RPort,Info->Labels[i],strlen(Info->Labels[i]),&Extent,NULL,1,Width,32767);
  843.  
  844.                             if(Len > MaxLen)
  845.                                 MaxLen = Len;
  846.                         }
  847.  
  848.                         if(MaxLen)
  849.                         {
  850.                             Len = strlen(Info->Labels[Info->Active]);
  851.  
  852.                             if(Len > MaxLen)
  853.                                 Len = MaxLen;
  854.  
  855.                             Info->ActiveLen = Len;
  856.  
  857.                             Info->MaxLen    = MaxLen;
  858.                             Info->MaxWidth    = Width;
  859.  
  860.                             return((ULONG)object);
  861.                         }
  862.                     }
  863.  
  864.                     CloseFont(Info->Font);
  865.                     Info->Font = NULL;
  866.                 }
  867.             }
  868.         }
  869.  
  870.         CoerceMethod(class,object,OM_DISPOSE);
  871.     }
  872.  
  873.     return(0);
  874. }
  875.  
  876. STATIC ULONG
  877. ActiveMethod(struct IClass *class,struct Gadget *gadget,struct gpInput *InputInfo)
  878. {
  879.     PopInfo                *Info = INST_DATA(class,gadget);
  880.     struct RastPort        *RPort;
  881.     struct GadgetInfo    *GInfo;
  882.  
  883.     if(Info->Blocked || (gadget->Flags & GFLG_DISABLED))
  884.         return(GMR_NOREUSE);
  885.  
  886.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  887.  
  888.     GInfo = InputInfo->gpi_GInfo;
  889.  
  890.     if(RPort = ObtainGIRPort(GInfo))
  891.     {
  892.         LONG Left,Top;
  893.  
  894.         Left    = gadget->LeftEdge;
  895.         Top        = gadget->TopEdge;
  896.  
  897.         Info->Window = NULL;
  898.  
  899.         if(Info->NumLabels > 2 && InputInfo->gpi_Mouse.X >= Info->MarkLeft)
  900.         {
  901.             LONG SingleHeight,ScreenHeight,Width,Height;
  902.  
  903.             Info->Flags &= ~PIF_SingleActive;
  904.             Info->Window = NULL;
  905.  
  906.             SetFont(RPort,Info->Font);
  907.  
  908.             SingleHeight = gadget->Height;
  909.             ScreenHeight = GInfo->gi_Screen->Height;
  910.  
  911.             Info->LineTop = (SingleHeight - RPort->TxHeight) / 2;
  912.  
  913.             Width    = Info->PopWidth;
  914.             Height    = 2 + SingleHeight * Info->NumLabels + 2;
  915.  
  916.             while(Height > SingleHeight && Height > ScreenHeight)
  917.                 Height -= SingleHeight;
  918.  
  919.             if(Height > SingleHeight)
  920.             {
  921.                 struct DrawInfo *DrawInfo;
  922.                 UWORD *Pens;
  923.                 LONG LeftEdge,TopEdge;
  924.                 LONG TopMost;
  925.                 LONG Plus;
  926.  
  927.                 LeftEdge    = GInfo->gi_Window->LeftEdge + Left + Info->PopLeft;
  928.                 TopEdge        = GInfo->gi_Window->TopEdge + Top + Info->LabelTop - (2 + Info->LineTop + Info->Active * SingleHeight);
  929.                 TopMost        = 0;
  930.  
  931.                 if(Info->CentreActive)
  932.                     Plus = 1;
  933.                 else
  934.                     Plus = 0;
  935.  
  936.                 while(TopEdge < 0 && TopMost < Info->NumLabels)
  937.                 {
  938.                     TopEdge    += SingleHeight;
  939.                     TopMost    += Plus;
  940.                 }
  941.  
  942.                 DrawInfo = GInfo->gi_DrInfo;
  943.                 Pens = DrawInfo->dri_Pens;
  944.  
  945.                 if(V39)
  946.                 {
  947.                     Info->MenuText = Pens[BARDETAILPEN];
  948.                     Info->MenuBack = Pens[BARBLOCKPEN];
  949.                 }
  950.                 else
  951.                 {
  952.                     Info->MenuText = Pens[DETAILPEN];
  953.                     Info->MenuBack = Pens[BLOCKPEN];
  954.                 }
  955.  
  956.                 Info->CheckGlyph = LTP_CreateCheckGlyph((RPort->TxHeight * DrawInfo->dri_Resolution.Y) / DrawInfo->dri_Resolution.X,RPort->TxHeight,GInfo->gi_Window->RPort->BitMap,Info->MenuText,Info->MenuBack);
  957.  
  958.                 if(Info->CheckGlyph && TopEdge >= 0 && TopMost < Info->NumLabels)
  959.                 {
  960.                     while(Height > SingleHeight && TopEdge + Height > ScreenHeight)
  961.                         Height -= SingleHeight;
  962.  
  963.                     if(Height > SingleHeight && TopEdge + Height <= ScreenHeight)
  964.                     {
  965.                         ReleaseGIRPort(RPort);
  966.  
  967.                         if(Info->Window = OpenWindowTags(NULL,
  968.                             WA_Left,            LeftEdge,
  969.                             WA_Top,                TopEdge,
  970.                             WA_Width,            Width,
  971.                             WA_Height,            Height,
  972.                             WA_SimpleRefresh,    TRUE,
  973.                             WA_NoCareRefresh,    TRUE,
  974.                             WA_AutoAdjust,        FALSE,
  975.                             WA_CustomScreen,    GInfo->gi_Screen,
  976.                             WA_Borderless,        TRUE,
  977.  
  978.                             V39 ? WA_BackFill : TAG_IGNORE,LAYERS_NOBACKFILL,
  979.                         TAG_DONE))
  980.                         {
  981.                             Info->TopMost        = TopMost;
  982.  
  983.                             Info->BoxLeft        = LeftEdge + 4;
  984.                             Info->BoxTop        = TopEdge + 2;
  985.                             Info->BoxWidth        = Width - 8;
  986.                             Info->BoxHeight        = Height - 4;
  987.  
  988.                             Info->BoxLines        = Info->BoxHeight / SingleHeight;
  989.  
  990.                             Info->SingleWidth    = Width - 8;
  991.                             Info->SingleHeight    = SingleHeight;
  992.  
  993.                             if(V39)
  994.                             {
  995.                                 STATIC BYTE RenderPens[] =
  996.                                 {
  997.                                     BACKGROUNDPEN,
  998.                                     FILLPEN,
  999.                                     TEXTPEN,
  1000.                                     FILLTEXTPEN,
  1001.                                     SHADOWPEN,
  1002.                                     SHINEPEN,
  1003.                                     BARDETAILPEN,
  1004.                                     BARBLOCKPEN
  1005.                                     -1
  1006.                                 };
  1007.  
  1008.                                 LONG i,Pen,Max = 0;
  1009.  
  1010.                                 Info->MenuTextSelect    = Pens[BARBLOCKPEN];
  1011.                                 Info->MenuBackSelect    = Pens[BARDETAILPEN];
  1012.  
  1013.                                 for(i = 0 ; RenderPens[i] != -1 ; i++)
  1014.                                 {
  1015.                                     if((Pen = Pens[RenderPens[i]]) > Max)
  1016.                                         Max = Pen;
  1017.                                 }
  1018.  
  1019.                                 SetMaxPen(Info->Window->RPort,Max);
  1020.                             }
  1021.                             else
  1022.                             {
  1023.                                 Info->MenuTextSelect    = ~Pens[DETAILPEN];
  1024.                                 Info->MenuBackSelect    = ~Pens[BLOCKPEN];
  1025.                             }
  1026.  
  1027.                             SetFont(Info->Window->RPort,Info->Font);
  1028.                         }
  1029.  
  1030.                         if(!(RPort = ObtainGIRPort(GInfo)))
  1031.                         {
  1032.                             if(Info->Window)
  1033.                             {
  1034.                                 CloseWindow(Info->Window);
  1035.                                 Info->Window = NULL;
  1036.                             }
  1037.                         }
  1038.                     }
  1039.                 }
  1040.             }
  1041.         }
  1042.  
  1043.         if(!Info->Window)
  1044.         {
  1045.             LTP_DeleteCheckGlyph(Info->CheckGlyph);
  1046.             Info->CheckGlyph = NULL;
  1047.  
  1048.             Info->Flags |= PIF_SingleActive;
  1049.         }
  1050.  
  1051.         if(((Info->Flags & PIF_SingleActive) || Info->Window) && RPort)
  1052.         {
  1053.             Info->InitialActive = Info->Active;
  1054.  
  1055.             gadget->Flags |= GFLG_SELECTED;
  1056.  
  1057.             if(!Info->CheckGlyph)
  1058.                 DoMethod((Object *)gadget,GM_RENDER,GInfo,RPort,GREDRAW_UPDATE);
  1059.  
  1060.             ReleaseGIRPort(RPort);
  1061.  
  1062.             if(Info->Window)
  1063.                 BoxRender(Info,GInfo->gi_DrInfo->dri_Pens,Info->Active,TRUE,TRUE,0);
  1064.  
  1065.             return(GMR_MEACTIVE);
  1066.         }
  1067.  
  1068.         if(RPort)
  1069.             ReleaseGIRPort(RPort);
  1070.     }
  1071.  
  1072.     return(GMR_NOREUSE);
  1073. }
  1074.  
  1075. STATIC ULONG
  1076. InactiveMethod(struct IClass *class,struct Gadget *gadget,struct gpGoInactive *InactiveInfo)
  1077. {
  1078.     PopInfo *Info = INST_DATA(class,gadget);
  1079.  
  1080.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  1081.  
  1082.     gadget->Flags &= ~GFLG_SELECTED;
  1083.  
  1084.     if(Info->Window || (Info->Flags & PIF_SingleActive))
  1085.     {
  1086.         struct RastPort    *RPort;
  1087.  
  1088.         if(Info->Window)
  1089.         {
  1090.             CloseWindow(Info->Window);
  1091.             Info->Window = NULL;
  1092.         }
  1093.  
  1094.         if(!Info->CheckGlyph)
  1095.         {
  1096.             if(RPort = ObtainGIRPort(InactiveInfo->gpgi_GInfo))
  1097.             {
  1098.                 DoMethod((Object *)gadget,GM_RENDER,InactiveInfo->gpgi_GInfo,RPort,GREDRAW_UPDATE);
  1099.                 ReleaseGIRPort(RPort);
  1100.             }
  1101.         }
  1102.  
  1103.         LTP_DeleteCheckGlyph(Info->CheckGlyph);
  1104.         Info->CheckGlyph = NULL;
  1105.  
  1106.         Info->Flags &= ~PIF_SingleActive;
  1107.     }
  1108.  
  1109.     return(0);
  1110. }
  1111.  
  1112. ULONG SAVE_DS ASM
  1113. LTP_PopupClassDispatcher(REG(a0) struct IClass *class,REG(a2) Object *object,REG(a1) Msg msg)
  1114. {
  1115.     switch(msg->MethodID)
  1116.     {
  1117.         case OM_NEW:
  1118.             return(NewMethod(class,object,(struct opSet *)msg));
  1119.  
  1120.         case OM_UPDATE:
  1121.         case OM_SET:
  1122.             SetMethod(class,(struct Gadget *)object,(struct opSet *)msg);
  1123.             break;
  1124.  
  1125.         case GM_RENDER:
  1126.             return(RenderMethod(class,(struct Gadget *)object,(struct gpRender *)msg));
  1127.  
  1128.         case GM_HITTEST:
  1129.             return(GMR_GADGETHIT);
  1130.  
  1131.         case GM_GOINACTIVE:
  1132.             return(InactiveMethod(class,(struct Gadget *)object,(struct gpGoInactive *)msg));
  1133.  
  1134.         case GM_GOACTIVE:
  1135.             return(ActiveMethod(class,(struct Gadget *)object,(struct gpInput *)msg));
  1136.  
  1137.         case GM_HANDLEINPUT:
  1138.             return(InputMethod(class,(struct Gadget *)object,(struct gpInput *)msg));
  1139.  
  1140.         case OM_DISPOSE:
  1141.             DisposeMethod(class,object,msg);
  1142.  
  1143.             // Falls down to the default case...
  1144.     }
  1145.  
  1146.     return(DoSuperMethodA(class,object,msg));
  1147. }
  1148.  
  1149. #endif    // defined(DO_POPUP_KIND) && defined(DO_BOOPSI_KIND)
  1150.